const http = require('http');
const WebSocket = require('ws');

const CONFIG = {
    server: { host: 'localhost', port: 3000 },
    user: { mobile: '17091271111', passwordHash: 'e10adc3949ba59abbe56e057f20f883e' },
};

class VipTester {
    constructor() {
        this.ws = null;
        this.token = '';
        this.characters = [];
        this.selected = null;
    }

    async run() {
        await this.login();
        await this.connect();
        await new Promise(r => setTimeout(r, 600));
        await this.queryRoles();
        await this.selectFirstRole();
        await new Promise(r => setTimeout(r, 600));

        // 重置 VIP 并查询
        await this.resetVip();
        await this.queryVipInfo(-2);

        // 记录金币
        const before = await this.query1451();
        console.log(`[1451] before gold=${before.gold}, money=${before.money}`);

        // 61020 注入20000 VIP 经验
        await this.injectVipExp(20000);

        const after = await this.query1451();
        console.log(`[1451] after  gold=${after.gold}, money=${after.money}  Δgold=${after.gold - before.gold}`);

        // 再次查询 6102
        const info = await this.queryVipInfo(-2);
        const vipLvl = info?.data?.vipLvl ?? -1;
        console.log(`[ASSERT] vipLvl=${vipLvl} >= 2 ?`, vipLvl >= 2);

        // 6153 领取每日经验
        await this.claimVipDailyExp();

        // 校验 6102 各等级特权条数
        await this.testVipPrivilegeCounts();

        this.ws && this.ws.close();
    }

    async login() {
        const body = await this.http('/user-service/user/login', 'POST', {
            mobile: CONFIG.user.mobile,
            pwd: CONFIG.user.passwordHash,
        });
        if (body.code !== 0) throw new Error('login failed: ' + body.msg);
        this.token = body.data.accessToken;
    }

    async connect() {
        const url = `ws://${CONFIG.server.host}:${CONFIG.server.port}/user-service/websocket?t=${this.token}`;
        this.ws = await new Promise((resolve, reject) => {
            const w = new WebSocket(url);
            w.on('open', () => resolve(w));
            w.on('error', reject);
        });
    }

    async queryRoles() {
        const res = await this.sendAndWait(m => m.act_id === 3, { c: 3, d: null });
        this.characters = res.roleList || [];
        if (!this.characters.length) throw new Error('no roles');
    }

    async selectFirstRole() {
        const role = this.characters[0];
        await this.sendAndWait(m => m.act_id === 4, { c: 4, d: { characterId: role.id } });
        this.selected = role;
    }

    async queryVipInfo(lvl) {
        const res = await this.sendAndWait(m => m.act_id === 6102, { c: 6102, d: { lvl } });
        console.log(`[6102] lvl=${lvl} => vipLvl=${res.data.vipLvl}, next=${res.data.next}, list.len=${(res.data.list || []).length}`);
        return res;
    }

    async injectVipExp(amount) {
        const res = await this.sendAndWait(m => m.act_id === 61020, { c: 61020, d: { next: amount } });
        if (res.code && res.code !== 0) {
            console.log(`[61020] failed: ${res.msg}`);
        } else {
            console.log(`[61020] ok ->`, res.data);
        }
    }

    async claimVipDailyExp() {
        const res = await this.sendAndWait(m => m.act_id === 6153, { c: 6153, d: { t: 2, lvl: 3 } });
        if (res.code === 8) console.log('[6153] already claimed or not enough online time');
        else if (res.code === 0) console.log('[6153] claim ok');
        else console.log('[6153] failed:', res.msg);
    }

    async resetVip() {
        await this.sendAndWait(m => m.act_id === 61021, { c: 61021, d: {} });
        console.log('[61021] reset ok');
    }

    async testVipPrivilegeCounts() {
        const expected = { 0: 3, 1: 5, 2: 7, 3: 10, 4: 9, 5: 9, 6: 10, 7: 11, 8: 12, 9: 12 };
        let pass = true;
        for (let lvl = 0; lvl <= 9; lvl++) {
            const res = await this.queryVipInfo(lvl);
            const got = (res?.data?.list || []).length;
            const exp = expected[lvl];
            const ok = got === exp;
            pass = pass && ok;
            console.log(`[CHECK 6102 lvl=${lvl}] list.length=${got} expected=${exp} -> ${ok ? 'PASS' : 'FAIL'}`);
        }
        console.log(`[CHECK 6102 ALL LEVELS] ${pass ? 'ALL PASS' : 'HAS FAILURES'}`);
    }

    async query1451() {
        const res = await this.sendAndWait(m => m.act_id === 1451, { c: 1451, d: {} });
        return res.data || { gold: 0, money: 0 };
    }

    async sendAndWait(pred, payload, timeoutMs = 8000) {
        return new Promise((resolve, reject) => {
            let done = false;
            const handler = (data) => {
                try {
                    const msg = JSON.parse(data.toString());
                    if (pred(msg)) {
                        this.ws.removeListener('message', handler);
                        done = true;
                        resolve(msg);
                    }
                } catch (e) {
                    // ignore
                }
            };
            this.ws.on('message', handler);
            this.ws.send(JSON.stringify(payload));
            setTimeout(() => {
                if (!done) {
                    this.ws.removeListener('message', handler);
                    reject(new Error('timeout'));
                }
            }, timeoutMs);
        });
    }

    async http(path, method, data) {
        return new Promise((resolve, reject) => {
            const options = {
                hostname: CONFIG.server.host,
                port: CONFIG.server.port,
                path,
                method,
                headers: { 'Content-Type': 'application/json' },
            };
            const req = http.request(options, (res) => {
                let body = '';
                res.on('data', (c) => (body += c));
                res.on('end', () => {
                    try { resolve(JSON.parse(body)); } catch { resolve({}); }
                });
            });
            req.on('error', reject);
            if (data) req.write(JSON.stringify(data));
            req.end();
        });
    }
}

if (require.main === module) {
    new VipTester().run().catch((e) => {
        console.error('VIP test failed:', e.message);
        process.exit(1);
    });
}


